// 泛型
function log<T>(value: T): T{
  console.log(value);
  return value;
}

log<string []>(['a', 'b']);
log(['a', 'b']);

// 用类型来定义函数类型

// 我们使用类型别名定义一个泛型函数类型
type Log = <T>(value: T) => T; // 等号后面我们需要把函数的名称去掉

let myLog: Log = log;

// 泛型接口

// 泛型同样可以用在接口中
// 在这里呢泛型仅仅约束了一个函数
interface LogInter{
  <T>(value: T): T // 同样要去掉函数名称，这样和类型别名的定义是完全等价的
}

// 我们也可以用泛型来约束接口的其它成员，方法呢就是把这个泛型变量 T 把它放在接口名称的后面，
// 这样接口的所有成员都可以受到泛型变量的约束了
// 这里需要注意一点：当泛型变量约束了整个接口之后在实现的时候我们必须指定一个类型
interface LogInter1<T>{
  (value: T): T
}

let myLog1: LogInter1<number> = log; // 这里我们指定一个number类型，那么 myLog1 的参数只能是 number
myLog1(1);

// 如果不指定类型我们也可以在接口的定义中指定一个默认的类型
interface LogInter2<T = string>{
  (value: T): T
}
let myLog2: LogInter2 = log;
myLog2('100');
